﻿using System;

namespace NRank.Common
{
	/// <summary>
	/// Class wrapping the threshold count algorithm for top-k algorithms.
	/// </summary>
	public class ThresholdCounter
	{
		/// <summary>
		/// Left source bounds
		/// </summary>
		private readonly IBoundHolder leftSourceBounds;

		/// <summary>
		/// Right source bounds
		/// </summary>
		private readonly IBoundHolder rightSourceBounds;

		/// <summary>
		/// Aggregate function
		/// </summary>
		private readonly Func<double, double, double> aggregateFunc;

		/// <summary>
		/// Creates instance of ThresholdCounter
		/// </summary>
		/// <param name="leftSourceBounds">Left source bounds provider</param>
		/// <param name="rightSourceBounds">Right source bounds provider</param>
		/// <param name="aggregateFunc">Aggregate function</param>
		public ThresholdCounter(IBoundHolder leftSourceBounds, IBoundHolder rightSourceBounds, Func<double,double,double> aggregateFunc)
		{
			this.leftSourceBounds = leftSourceBounds;
			this.rightSourceBounds = rightSourceBounds;
			this.aggregateFunc = aggregateFunc;
		}

		/// <summary>
		/// Counts current threshold
		/// </summary>
		/// <returns>Current threshold</returns>
		public double CountThreshold()
		{
			return Math.Max(aggregateFunc(this.leftSourceBounds.MaxRank, this.rightSourceBounds.MinRank),
			                aggregateFunc(this.leftSourceBounds.MinRank, this.rightSourceBounds.MaxRank));
		}

		/// <summary>
		/// Determines if left source blocks the minimal value of threshold
		/// </summary>
		/// <returns></returns>
		public bool IsLeftMinBlockingThreshold()
		{
			return CountThreshold() == aggregateFunc(leftSourceBounds.MinRank, rightSourceBounds.MaxRank);
		}

		/// <summary>
		/// Determines if right source blocks the minimal value of threshold
		/// </summary>
		/// <returns></returns>
		public bool IsRightMinBlockingThreshold()
		{
			return CountThreshold() == aggregateFunc(leftSourceBounds.MaxRank, rightSourceBounds.MinRank);
		}
	}
}